﻿using DxfLib;
using DxfOk.Model;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;

namespace DxfOk.ViewModel
{
    public class DxfItemViewModel : ObservableObject
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger
         (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public static Regex regCopiedTextIndexedFolder = new Regex(@"\s*【(\d\d\d)】.*");
        public static Regex regCopiedTextFolder = new Regex(@"\s*【(\d\d\d)】、.*");
        public static Regex regCopiedTextFile = new Regex(@"\s*【\d\d\d】\s*(.+)");
        private string folderIndexString;
        public DxfItemViewModel(string copiedText)
        {
            this.CopiedText = copiedText;
            ReMatchCopied();
            //this.MoveHasError = true;
            //this.MoveExceptionMessage = "MoveExceptionMessage";
        }

        private void ReMatchCopied()
        {
            DxfType dxfTypeFolderMatch = DxfType.Unknown;
            DxfType dxfTypeFolderExist = DxfType.Unknown;
            DxfType dxfTypeFileExist = DxfType.Unknown;
            DxfType dxfNodeType = DxfType.Unknown;
            RealFolderName = null;
            RealFileName = null;
            if (regCopiedTextIndexedFolder.IsMatch(CopiedText))//TODO: remove because main filtered
            {
                folderIndexString = regCopiedTextIndexedFolder.Match(copiedText).Groups[1].Value;
                string? folderByIndex = DxfUtils.searchFolderByIndex(folderIndexString);
                if (folderByIndex == null)
                {
                    dxfTypeFolderMatch = DxfType.FolderNotMatch;
                }
                else
                {
                    dxfTypeFolderMatch = DxfType.FolderMatch;
                    RealFolderName = DxfUtils.SearchRealDir(folderByIndex);
                    if (RealFolderName != null
                        && !DxfUtils.AllRealFolders.Contains(RealFolderName))
                    {
                        //add folders to check all
                        DxfUtils.AllRealFolders.Add(RealFolderName);
                    }
                    if (RealFolderName == null)
                    {
                        dxfTypeFolderExist = DxfType.FolderNotExist;
                    }
                    else
                    {
                        dxfTypeFolderExist = DxfType.FolderExist;

                    }
                }
                if (regCopiedTextFolder.IsMatch(copiedText))
                {
                    dxfNodeType = DxfType.Folder;
                }
                else if (regCopiedTextFile.IsMatch(copiedText))
                {
                    dxfNodeType = DxfType.File;

                    string fileName = regCopiedTextFile.Match(copiedText).Groups[1].Value + ".dxf";
                    //log.Debug($"checking {fileName}");
                    if (dxfTypeFolderExist == DxfType.FolderExist)
                    {
                        string fullName = Path.GetFullPath(Path.Combine(RealFolderName, fileName));
                        if (File.Exists(fullName))
                        {
                            dxfTypeFileExist = DxfType.FileExist;
                            RealFileName = fullName;
                        }
                        else
                        {
                            string removedOkFull = DxfUtils.RemoveOk(fullName);
                            if (File.Exists(removedOkFull))
                            {
                                dxfTypeFileExist = DxfType.FileExist;
                                RealFileName = removedOkFull;
                                log.Debug($"remove ok exist {removedOkFull}");

                            }

                            else
                            {
                                string? fuzzyFull = Directory.GetFiles(RealFolderName, "*.dxf").FirstOrDefault(x =>
                                DxfUtils.AreSameIgnoreOk(x, fullName));
                                if (fuzzyFull == null)
                                {
                                    dxfTypeFileExist = DxfType.FileNotExist;
                                }
                                else
                                {
                                    RealFileName = fuzzyFull;
                                    dxfTypeFileExist = DxfType.FileExist;
                                    log.Debug($"fuzzy exist {fuzzyFull}");

                                }
                            }
                        }

                    }

                }
                DxfType = dxfTypeFolderMatch | dxfTypeFolderExist | dxfTypeFileExist | dxfNodeType;

            }
            else
            {
                DxfType = DxfType.Unknown;
            }
        }


        private DxfType dxfType;
        public DxfType DxfType
        {
            get => dxfType;
            set
            {
                SetProperty(ref dxfType, value);
            }
        }

        public string DxfStatusMessage
        {
            get
            {
                //ReMatchCopied();
                if ((this.DxfType & DxfType.File) == DxfType.File)
                {
                    if ((this.DxfType & DxfType.FileExist) == DxfType.FileExist)
                    {
                        log.Debug($"DxfType.FileExist,{RealFileName}");
                        Message = RealFileName;
                        if (DxfUtils.ContainsOk(Path.GetFileNameWithoutExtension(RealFileName)))
                            return "√";
                        else
                            return "×";
                    }
                    if ((this.DxfType & DxfType.FolderNotMatch) == DxfType.FolderNotMatch)
                        return "???";
                    if ((this.DxfType & DxfType.FolderMatch) == DxfType.FolderMatch)
                    {
                        if ((this.DxfType & DxfType.FolderNotExist) == DxfType.FolderNotExist)
                        {
                            return "??";
                        }
                        if ((this.DxfType & DxfType.FolderExist) == DxfType.FolderExist)
                        {
                            if ((this.DxfType & DxfType.FileNotExist) == DxfType.FileNotExist)
                                return "?";
                        }
                    }
                }
                if ((this.DxfType & DxfType.Folder) == DxfType.Folder)
                {
                    if ((this.DxfType & DxfType.FolderMatch) == DxfType.FolderMatch)
                    {
                        if ((this.DxfType & DxfType.FolderExist) == DxfType.FolderExist)
                        {
                            Message = RealFolderName;
                            if (DxfUtils.AreAllFilesUnderFolderOk(RealFolderName))
                                return "已完成";
                            else
                                return "进行中";
                        }
                        if ((this.DxfType & DxfType.FolderNotExist) == DxfType.FolderNotExist)
                        {
                            return "找不到";
                        }
                    }
                    if ((this.DxfType & DxfType.FolderNotMatch) == DxfType.FolderNotMatch)
                    {
                        return "无索引";
                    }
                }
                return "未知状态";
            }



        }

        private bool IsPathProtected()
        {
            return DxfUtils.AllProtectedFolders != null
                && DxfUtils.AllProtectedFolders.Any(x => RealFolderName == x);
        }

        public bool SetOk()
        {
            //TODO: exception
            if ((this.DxfType & DxfType.FileExist) == DxfType.FileExist)
            //TODO: if real file changed
            {
                MoveHasError = false;
                string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(RealFileName);
                string newFileNameWithoutExtension = DxfUtils.SetOk(fileNameWithoutExtension);
                if (fileNameWithoutExtension == newFileNameWithoutExtension)
                    return false;
                if (IsPathProtected())
                {
                    log.Info($"跳过{RealFileName}添加ok，因为文件夹被保护。");
                    return false;
                }
                string newFullName = Path.Combine(Path.GetDirectoryName(RealFileName), newFileNameWithoutExtension + ".dxf");
                log.Debug($"准备添加ok {RealFileName}");
                try
                {
                    File.Move(RealFileName, newFullName);
                    log.Info($"重命名 {RealFileName} --> {newFullName}");
                    RealFileName = newFullName;
                    InvalidateStatus();
                    return true;

                }
                catch (Exception ex)
                {
                    MoveHasError = true;
                    MoveExceptionMessage = $"重命名失败，{ex.Message}";
                    log.Error(MoveExceptionMessage);

                    return false;
                }

            }
            return false;
        }

        public bool RemoveOk()
        {
            //TODO: exception
            if ((this.DxfType & DxfType.FileExist) == DxfType.FileExist)
            //TODO: if real file changed
            {
                MoveHasError = false;
                string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(RealFileName);
                string newFileNameWithoutExtension = DxfUtils.RemoveOk(fileNameWithoutExtension);
                if (fileNameWithoutExtension == newFileNameWithoutExtension)
                    return false;
                if (IsPathProtected())
                {
                    log.Info($"跳过{RealFileName}移除ok，因为文件夹被保护。");
                    return false;
                }
                string newFullName = Path.Combine(Path.GetDirectoryName(RealFileName), newFileNameWithoutExtension + ".dxf");
                log.Debug($"准备移除ok {RealFileName}");
                try
                {
                    File.Move(RealFileName, newFullName);
                    log.Info($"重命名 {RealFileName} --> {newFullName}");
                    RealFileName = newFullName;
                    InvalidateStatus();
                    return true;

                }
                catch (Exception ex)
                {
                    MoveHasError = true;
                    MoveExceptionMessage = $"重命名失败，{ex.Message}";
                    log.Error(MoveExceptionMessage);
                    return false;
                }

            }
            return false;
        }

        public void RefreshIfFolderExist()
        {
            if ((this.DxfType & DxfType.FolderExist) == DxfType.FolderExist)
            {
                InvalidateStatus();
            }
        }

        public void InvalidateStatus()
        {
            //TODO: files
            OnPropertyChanged(nameof(DxfStatusMessage));
        }

        public string? RealFolderName { get; set; }
        public string? RealFileName { get; set; }



        private string folderFull;
        public string FolderFull
        {
            get => folderFull;
            set
            {
                SetProperty(ref folderFull, value);
            }
        }

        private string copiedText;
        public string CopiedText
        {
            get => copiedText;
            set
            {
                SetProperty(ref copiedText, value);
            }
        }

        private bool moveHasError;
        public bool MoveHasError
        {
            get => moveHasError;
            set
            {
                SetProperty(ref moveHasError, value);
            }
        }

        private string moveExceptionMessage;
        public string MoveExceptionMessage
        {
            get => moveExceptionMessage;
            set
            {
                SetProperty(ref moveExceptionMessage, value);
            }
        }


        private string message;
        public string Message
        {
            get => message;
            set
            {
                SetProperty(ref message, value);
            }
        }

        //openfolder

        private RelayCommand openfolderCommand;
        public RelayCommand OpenFolderCommand => openfolderCommand ?? (openfolderCommand = new RelayCommand(ExecuteOpenFolderCommand, CanExecuteOpenFolderCommand));

        private bool CanExecuteOpenFolderCommand()
        {
            return !isOpenFolderning && (this.DxfType & DxfType.FolderExist) == DxfType.FolderExist;
        }



        private bool isOpenFolderning;
        private void ExecuteOpenFolderCommand()
        {
            isOpenFolderning = true;
            OpenFolderCommand.NotifyCanExecuteChanged();
            string argument = RealFolderName;
            if (RealFileName != null && File.Exists(RealFileName))
            {
                argument = "/select, \"" + RealFileName + "\"";
            }
            Process.Start("explorer.exe", argument);
            log.Info($"打开文件夹{argument}");
            isOpenFolderning = false;
            OpenFolderCommand.NotifyCanExecuteChanged();
        }

        //open file

        private RelayCommand openfileCommand;
        public RelayCommand OpenFileCommand => openfileCommand ?? (openfileCommand = new RelayCommand(ExecuteOpenFileCommand, CanExecuteOpenFileCommand));

        private bool CanExecuteOpenFileCommand()
        {
            return !isOpenFilening && (this.DxfType & DxfType.FileExist) == DxfType.FileExist;
        }



        private bool isOpenFilening;
        private void ExecuteOpenFileCommand()
        {
            if (!CanExecuteOpenFileCommand())
                return;
            isOpenFilening = true;
            OpenFileCommand.NotifyCanExecuteChanged();
            string fullName = RealFileName;
            var psi = new ProcessStartInfo();
            psi.UseShellExecute = true;
            psi.FileName = fullName;
            try
            {
                Process.Start(psi);
                log.Info($"打开文件{fullName}");
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            isOpenFilening = false;
            OpenFileCommand.NotifyCanExecuteChanged();
        }
    }
}
